package AI;

import java.util.Random;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import orfeu.engine.*;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.opengl.GLUtils;
import android.util.Log;

public class Demon extends Sprite{

	public float health; 
	public float baseDamage;
	public float impactDamage;
	private float moveSpeed;
	public boolean flyer = false;
	public boolean exploder = false;
	private int stop ;
	private int proj_rate;
	private long last_time;
	public boolean crawler;
	public static int demonCount = 0;
	
	
	public Demon(float w, float h, int nf, long fp, int res) {
		super(w, h, nf, fp, res);
		this.createDemon();
		this.spawn();
		last_time = System.currentTimeMillis();
		proj_rate = 6000;
		
	}
	
	private void createDemon() {
		Random generator = new Random();
		float type = generator.nextFloat() * 3;

		if (type < 0.5) {
			type += 1.5; //bonus health
			this.moveSpeed = 2 * Hell.SPEED;
			//this.setSpeed(this.moveSpeed);
			this.impactDamage = Hell.ATTACK;
		}
		
		else if (type < 1.5) {
			type -= 0.5;
			this.flyer = true;
			this.moveSpeed = Hell.SPEED/2;
			//this.setSpeed(this.moveSpeed);
			if (type < 1) 
				this.baseDamage = 3 * Hell.ATTACK;
			else 
				this.baseDamage = 2 * Hell.ATTACK;
			if (type > 1) {
				if (generator.nextInt() % 2 == 0) {
					this.exploder = true;
					this.impactDamage = (generator.nextInt(6) + 1) * Hell.ATTACK;
					type -= 0.25; //penalizare ca explodeaza
					
				}
			}
		}
		
		else if (type < 2.5) {
			type -= 1;
			this.exploder = true;
			if (type < 2) {
				if (generator.nextInt() % 2 == 0) {
						this.flyer = true;
						this.baseDamage = 2 * Hell.ATTACK;
						type -= 0.25; //penalizare ca explodeaza
						
				}
				this.moveSpeed = 3 * Hell.SPEED;
				//this.setSpeed(this.moveSpeed);
			}
			else {
				this.moveSpeed = 2 * Hell.SPEED;
				//this.setSpeed(this.moveSpeed);
			}
			this.impactDamage = 8 * Hell.ATTACK;
		}
		
		else {
			type -= 1.5;
			if (generator.nextInt() % 2 == 0) {
				this.exploder = true;
			}
			this.moveSpeed = 2 * Hell.SPEED;
			//this.setSpeed(this.moveSpeed);
			this.impactDamage = (generator.nextInt(6) + 1) * Hell.ATTACK;
		}
		
		this.health = Math.round(type * Hell.HEALTH);
		if (this.flyer){
			this.resource = R.drawable.flyer;
			this.stop = (int)(generator.nextInt()%Constants.limitDown);
			
			
			}
		else if (this.exploder)
			this.resource = R.drawable.exploder;
		else
			this.resource = R.drawable.crawler;
		Hell.demons.add(this);
		
		Log.d("i", "" + this.flyer);
		
	}
	
	
	public String toString() {
		String s = "health: " + this.health + ", exploder: " + this.exploder
				+ ", flyer: " + this.flyer + ", baseDamage: " + this.baseDamage +
				", impactDamage: " + this.impactDamage + ", moveSpeed: " + this.moveSpeed
				+ ", resource: " + this.resource;
		return s;
	}
	
	public float getHealth() {
		return this.health;
	}
	
	public void setHealth(float health) {
		this.health = health;
	}
	
	public void updateHealth(float damage) {
		this.health -= damage;
	}
	
	public boolean isAlive() {
		return this.health > 0;
	}
	
	public void spawn() {
		Random generator = new Random();
		this.px = generator.nextInt((int)(Constants.limitRight - Constants.limitLeft)) + Constants.limitLeft;
		this.py = Constants.limitDown;
		//this.px = this.py = 0;
	}
	
	@Override
	public boolean outOfBounds()
	{
		if(this.py >= Constants.limitUp || this.py <= Constants.limitDown
				|| this.px > Constants.limitRight || this.px < Constants.limitLeft)
			return true;
		return false;
	}
	
	@Override
	public void update(long time) {
		tick(time);
		this.py += this.moveSpeed;
		
		// keep object in some bounds, depending on the demon type
		if (!this.flyer && !this.exploder) {
			if (this.py > Constants.limitUp) 
			{
				
				this.py = Constants.limitDown;
			}
		}
		else if(this.flyer && !this.exploder) 
		{
			if(py >= stop)
				py = stop;
			
		}
		else if(this.exploder && !this.flyer){
			//TODO: Daca ajunge in dreptul eroului face boom
			if (this.py > Constants.limitUp){
				this.explode();
				this.setRemove();
			}
			
		}
			
		//Make flye demon create projectiles
		if(this.flyer)
		{
			if(time >= last_time + proj_rate)
			{
				this.createProjectile();
				last_time = time;
			}
		}
		
	}
	
	@Override
	/** function that loads a texture **/
	public void loadTexture(GL10 gl, Context context) {
		int id = textureId;
		
		// flip the texture vertically
		Matrix flip = new Matrix();
		flip.postScale(1f, -1f);
		
		// tell BitmapFactory not to scale image
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inScaled = false;
		
		// load and flip the texture
		Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource, opts);
		spriteImage = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
		temp.recycle();
		
		gl.glBindTexture(GL10.GL_TEXTURE_2D, id);
		
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
		
		// generate and load mipmaps
		int[] crop = {0, spriteImage.getWidth(), spriteImage.getHeight(), -spriteImage.getHeight()};
		((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, crop, 0);
		for(int level=0, height = spriteImage.getHeight(), width = spriteImage.getWidth(); true; level++) {
	        // push the bitmap onto the GPU:
	        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, spriteImage, 0);
	        
	        // we need to stop when the texture is 1x1:
	        if(height==1 && width==1) break;
	        
	        // resize, and let's go again:
	        width >>= 1; height >>= 1;
	        if (width < 1)  
	        	width = 1;
	        if (height < 1) 
	        	height = 1;
	        
	        Bitmap bmp2 = Bitmap.createScaledBitmap(spriteImage, width, height, true);
	        spriteImage.recycle();
	        spriteImage = bmp2;
	    }
	    
		spriteImage.recycle();
	    
	    textureId = id;	
	}
	
	//Metoda pentru crearea proiectilelor zburatorilor
	public void createProjectile() {
		Projectile p = new Projectile(16, 16, 1, 100, R.drawable.icon);
		p.setDamage(this.baseDamage);
		p.setPosition(this.px, this.py + this.height/1.5f);
		//Log.d("i", "sprite: " + this.px + " " + this.py +
		//		"; proiectil: " + p.px + " " + p.py);
		p.setSpeed(2 * this.moveSpeed);
		p.textureId = Hell.firstProjectile.textureId;
		//Adaugam in drawlist
		synchronized (GLView.getRenderer().drawList) {
			GLView.getRenderer().drawList.add(p);
			GLView.getRenderer().drawList.notifyAll();
		}
		//Adaugam proiectilul in updateList
		synchronized(GLView.getUpdater().updateList){
			GLView.getUpdater().updateList.add(p);
			GLView.getUpdater().updateList.notifyAll();
		}
		//Adaugam proiectilul in Lista de proiectile
		synchronized(Hell.enemyProjectiles){
			Hell.enemyProjectiles.add(p);
			Hell.enemyProjectiles.notifyAll();
		}
	}
	
	public void explode () {
		Hero h = Hero.getHero();
		Demon d = new Demon(this.width, this.height, this.noFrames, this.framePeriod, this.resource);
		d.px = this.px; d.py = this.py;
		for (int i = 2; i <= 4; i++){
			d.width *= 2;
			d.height *= 2;
			if (h.collidesWith(d)) {
				h.updateHealth(this.impactDamage/i);
				return;
			}
		}
	}
}
